#pragma once

#include<iostream>
#include<pthread.h>
#include<queue>

namespace wyl
{
    const int default_num = 5;
    template<class T>
    class Thread_pool
    {
    private:
        int _num;
        std::queue<T> _sq;
        pthread_mutex_t _mutex; //锁
        pthread_cond_t _cond; //条件变量
    
    private:

        void Lock()
        {
            pthread_mutex_lock(&_mutex);
        }
        void UnLock()
        {
            pthread_mutex_unlock(&_mutex);
        }
        void Wait()
        {
            pthread_cond_wait(&_cond,&_mutex);
        }
        void Wakeup()
        {
            pthread_cond_signal(&_cond);
        }
        bool IsEmpty()
        {
            return 0 == _sq.size();
        }
        static void* Rountine(void* args)
        {
            //线程分离
            pthread_detach(pthread_self());
            Thread_pool<T>* tp = (Thread_pool<T>*)args;
            //处理任务
            while(true)
            {
                tp->Lock();
                //如果任务队列为空，则等待
                while(tp->IsEmpty()){
                    tp->Wait();
                }
                T t;
                tp->Pop(&t); //tp是临界资源，上锁
                tp->UnLock();
                t(); //t是线程独有的任务，并不是临界资源
            }
        }

        //任务执行完应该移除任务
        void Pop(T* out)
        {
            //当前线程已经持有锁了，所以不能上锁
            *out = _sq.front();
            _sq.pop();
        }

    public: 
         Thread_pool(int num = default_num)
         :_num(num)
         {
            pthread_mutex_init(&_mutex,nullptr);
            pthread_cond_init(&_cond,nullptr);
         }
         ~Thread_pool()
         {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond);
         }

        //初始化线程池
        void Pool_Init()
        {
            pthread_t tid;
            for(int i = 0 ; i < _num;i++)
            {
                //创建num个线程
                pthread_create(&tid,nullptr,Rountine,(void*)this); //因为Rountine是静态函数，所以传自己的指针
            }
        }

        void Push(const T& in)
        {
            //把任务放进等待队列
            Lock();
            _sq.push(in); //临界资源，上锁
            UnLock();   
            //有数据后，唤醒任务中等待的线程
            Wakeup();
        }
    };
}